home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 11255 / 11255.xpi / chrome / content / controller / buttons / InButtonController.js < prev    next >
Text File  |  2009-12-16  |  34KB  |  991 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * 
  3.  * Pearltrees add-on AMO, Copyright(C), 2009, Broceliand SAS, Paris, France 
  4.  * (company in charge of developing Pearltrees)
  5.  * 
  6.  * This file is part of ΓÇ£Pearltrees add-on AMOΓÇ¥.  
  7.  * 
  8.  * Pearltrees add-on AMO is free software: you can redistribute it and/or modify it under the 
  9.  * terms of the GNU General Public License version 3 as published by the Free Software Foundation.
  10.  * 
  11.  * Pearltrees add-on AMO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
  12.  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
  13.  * See the GNU General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License along with Pearltrees add-on AMO. 
  16.  * If not, see <http://www.gnu.org/licenses/>
  17.  * 
  18.  * ***** END LICENSE BLOCK ***** */
  19.  
  20. // ///////////////////////////////////////////////////////////////////////////////
  21. // In button
  22. // ///////////////////////////////////////////////////////////////////////////////
  23.  
  24. var BRO_inButtonController = {
  25.         
  26.     _selectionChanged : false,
  27.     _selectedTree : null,
  28.     _selectedHistory : null,
  29.     _selectedNewHistory : null,
  30.     IS_NEWMAP_BUTTON_IN_LIST : false,
  31.     TREE_LIST_NEWMAP_INDEX : 0,
  32.     MAX_CHARS_IN_BUTTON_LABEL : 14,
  33.     
  34.     getSelectedTree : function() {
  35.         if(!this._selectedTree) return null;
  36.  
  37.         // Return tree object from the tree list
  38.         var treeList = BRO_model.getTreeList();
  39.         if (!treeList) {
  40.             return this._selectedTree;
  41.         }
  42.         
  43.         for (var i = 0; i < treeList.length; i++) {
  44.             if (treeList[i].treeID == this._selectedTree.treeID) {             
  45.                 return treeList[i];
  46.             }
  47.         }
  48.         return null;
  49.     },
  50.  
  51.     getSelectedHistory : function() {        
  52.         if(!this._selectedHistory) return null;
  53.  
  54.         // Return history object from the history list
  55.         var historyList = BRO_model.getHistoryList();
  56.         if (!historyList) {
  57.             return this._selectedHistory;
  58.         }
  59.         
  60.         for (var i = 0; i < historyList.length; i++) {
  61.             if (historyList[i].id == this._selectedHistory.id) {             
  62.                 return historyList[i];
  63.             }
  64.         }
  65.         return null;        
  66.     },
  67.  
  68.     getSelectedNewHistory : function() {
  69.         return this._selectedNewHistory;
  70.     },    
  71.     
  72.     initTreeList : function() {
  73.         // backup from preferences
  74.         var rootTree = BRO_toolbar.backupRootTreeFromPreferences();
  75.         var dropZone = BRO_toolbar.backupDropZoneFromPreferences();
  76.         var currentUser = BRO_toolbar.backupCurrentUserFromPreferences();
  77.         BRO_model.updateCurrentUser(currentUser);
  78.  
  79.         if (rootTree && !this.getSelectedTree() && !this.getSelectedHistory() && !this._selectedNewHistory) {            
  80.             // In order to select the tree we create a treeList with only one item
  81.             var treeList = new Array(rootTree, dropZone);
  82.             BRO_model.setTreeList(treeList);
  83.             BRO_windowManager.setTreeList(treeList);
  84.             // we rebuild the visual list
  85.             this.onTreeListLoaded();
  86.             // we add a loading... message to the list
  87.             this.appendLoadingMessageToTreeList();
  88.             // we select the root tree in the list
  89.             this.selectTree(rootTree.treeID, false, true);
  90.         }else{
  91.             // will refresh tree list label
  92.             BRO_inButtonController.refreshTreeListVisualComponents();
  93.         }
  94.     },
  95.     
  96.     onSelectTreeListItem : function(event) {
  97.         var treeListBox = document.getElementById('BRO_treeListBox');
  98.         if(treeListBox.selectedIndex < 0) return;
  99.         
  100.         var selectedValue = this.decodeListBoxItemValue(treeListBox.selectedItem);
  101.         var startHistoryAfterSelect = false;
  102.         if (BRO_toolbar.getRecordingMode() == RECORING_MODE_CONTINUOUS
  103.                 && BRO_toolbar.isRecording
  104.                 && BRO_inButtonController.isNewSelectedValueChangeSelectedTreeOrHistory()) {
  105.             startHistoryAfterSelect = true;
  106.         } else if (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE
  107.                 && BRO_toolbar.isCurrentUrlRecorded()
  108.                 && BRO_inButtonController.isNewSelectedValueChangeSelectedTreeOrHistory()) {
  109.             startHistoryAfterSelect = true;
  110.         }
  111.  
  112.         // If click on a tree
  113.         if (this.isSelectedListBoxItemIsTree()) {
  114.             this.selectTree(selectedValue.treeID, startHistoryAfterSelect);
  115.             BRO_inButtonController._selectionChanged = true;
  116.         }
  117.         // If click on a history
  118.         else if (this.isSelectedListBoxItemIsHistory()) {
  119.             this.selectHistory(selectedValue.id, startHistoryAfterSelect);
  120.             BRO_inButtonController._selectionChanged = true;
  121.         }
  122.         // If create new map is now selected
  123.         else if (BRO_inButtonController.IS_NEWMAP_BUTTON_IN_LIST && this.isSelectedListBoxItemIsCreateNewMap()) {
  124.             BRO_inButtonController.showNameMapWindow();
  125.         } else {
  126.             this.backupSelection();
  127.         }
  128.     },    
  129.     
  130.     closePopup : function() {
  131.         var newButtonPopup = document.getElementById("BRO_newButtonPopup");
  132.         if(newButtonPopup) {
  133.             newButtonPopup.hidePopup();
  134.         }
  135.         var newTreePanel = document.getElementById('BRO_newTreePanel');
  136.         if(newTreePanel) {
  137.             newTreePanel.hidePopup();
  138.         }
  139.     },
  140.     
  141.     isDropZoneSelected:function() {
  142.         var currentUser = BRO_model.getCurrentUser();
  143.         var selectedTree = BRO_inButtonController.getSelectedTree();
  144.         return (selectedTree && selectedTree.treeID == currentUser.dropZoneID);
  145.     },
  146.  
  147.     isNewSelectedValueChangeSelectedTreeOrHistory : function() {
  148.         var treeListBox = document.getElementById('BRO_treeListBox');
  149.         var selectedValue = this.decodeListBoxItemValue(treeListBox.selectedItem);
  150.  
  151.         if (this.isSelectedListBoxItemIsTree()) {
  152.             return (!this.getSelectedTree() || this.getSelectedTree().treeID != selectedValue.treeID);
  153.         } else if (this.isSelectedListBoxItemIsHistory()) {
  154.             return (!this.getSelectedHistory() || this.getSelectedHistory().id != selectedValue.id);
  155.         } else {
  156.             return false;
  157.         }
  158.     },
  159.  
  160.     isSelectedListBoxItemIsCreateNewMap : function() {
  161.         var treeListBox = document.getElementById('BRO_treeListBox');
  162.         var selectedValue = this
  163.                 .decodeListBoxItemValue(treeListBox.selectedItem);
  164.  
  165.         // Just checking index is not enaugh to detect user selection
  166.         if (treeListBox.currentIndex == BRO_inButtonController.TREE_LIST_NEWMAP_INDEX
  167.                 && !selectedValue
  168.                 && (this.getSelectedTree() || this.getSelectedHistory() || this._selectedNewHistory)) {
  169.             return true;
  170.         } else {
  171.             return false;
  172.         }
  173.     },
  174.  
  175.     isSelectedListBoxItemIsTree : function() {
  176.         var treeListBox = document.getElementById('BRO_treeListBox');
  177.         var selectedValue = this.decodeListBoxItemValue(treeListBox.selectedItem);
  178.         return (selectedValue && selectedValue.treeID && (!this.getSelectedTree() || selectedValue != this.getSelectedTree().treeID));
  179.     },
  180.  
  181.     isSelectedListBoxItemIsHistory : function() {
  182.         var treeListBox = document.getElementById('BRO_treeListBox');
  183.         var selectedValue = this.decodeListBoxItemValue(treeListBox.selectedItem);
  184.         return (selectedValue && selectedValue.id && selectedValue.name);
  185.     },
  186.  
  187.     onClickDefaultTreeListItem : function(event) {
  188.         BRO_toolbar.onUseToolbar();
  189.         // If create new map was already selected
  190.         if (!BRO_inButtonController._selectionChanged) {
  191.             BRO_inButtonController.showNameMapWindow();
  192.         }
  193.         BRO_inButtonController._selectionChanged = false;
  194.     },
  195.  
  196.     onClickTreeListItem : function(event) {
  197.         BRO_inButtonController.closePopup();
  198.  
  199.         if (BRO_toolbar.isPearltreesPublicUrl()) {
  200.             BRO_toolbar.openSelectedTreeInCurrentTab(null, true);
  201.         }
  202.         BRO_inButtonController._selectionChanged = false;
  203.     },
  204.  
  205.     onClickHistoryListItem : function(event) {
  206.         BRO_inButtonController.closePopup();
  207.  
  208.         BRO_inButtonController._selectionChanged = false;
  209.     },
  210.     
  211.     onNewTreePanelShowing:function() {
  212.         this.closePopup();
  213.         // Use small timeout whereas XBL setters don't work...
  214.         // Don't know why yet :(
  215.         BRO_tools.callWithDelay('BRO_inButtonController.initNewTreePanel()', 20);        
  216.     },
  217.     
  218.     initNewTreePanel:function() {
  219.         var newTreePanelContent = document.getElementById('BRO_newTreePanelContent');
  220.         newTreePanelContent.focus();
  221.         newTreePanelContent.text = "";        
  222.     },
  223.     
  224.     onClickCancelNewTree : function () {
  225.         BRO_inButtonController.closePopup();
  226.     },
  227.     
  228.     onClickValidateNewTree : function () {        
  229.         var newTreeTitle = document.getElementById('BRO_newTreePanelContent').text;    
  230.         if(newTreeTitle && BRO_tools.trim(newTreeTitle) != "") {
  231.             this.closePopup();
  232.         }
  233.         BRO_inButtonController.createNewTree(newTreeTitle);        
  234.     },    
  235.     
  236.     createNewTree : function(newTreeTitle) {            
  237.         if(!newTreeTitle || BRO_tools.trim(newTreeTitle) == "") {
  238.             return;
  239.         }
  240.         
  241.         this._selectedNewHistory = new Object;
  242.         this._selectedNewHistory.name = newTreeTitle;
  243.         var startHistoryAfterSelect = false;
  244.         if (BRO_toolbar.getRecordingMode() == RECORING_MODE_CONTINUOUS && BRO_toolbar.isRecording) {
  245.             startHistoryAfterSelect = true;
  246.         } 
  247.         else if (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE && BRO_toolbar.isCurrentUrlRecorded()) {
  248.             startHistoryAfterSelect = true;
  249.         }
  250.         else if(this.forceStartHistoryAfterSelect) {
  251.             startHistoryAfterSelect = true;
  252.         }
  253.         BRO_inButtonController.selectNewHistory(this._selectedNewHistory, startHistoryAfterSelect);
  254.         
  255.         if (!startHistoryAfterSelect) {
  256.             BRO_model.start(this._selectedNewHistory.name);
  257.         }
  258.         BRO_toolbar.isRevealed = false;
  259.         BRO_toolbar.showNameMapDoneWindow();        
  260.     },
  261.     
  262.     forceStartHistoryAfterSelect : false,
  263.  
  264.     showNameMapWindow : function(forceStartHistoryAfterSelect) {
  265.         this.forceStartHistoryAfterSelect = forceStartHistoryAfterSelect;        
  266.         BRO_toolbar.showNameMapWindow();    
  267.     },
  268.  
  269.     selectTree : function(treeID, startHistoryAfterSelect, isInitializing) {
  270.         this._selectedHistory = null;
  271.         BRO_windowManager.setSelectedHistory(null);
  272.         this._selectedNewHistory = null;
  273.         BRO_windowManager.setSelectedNewHistory(null);
  274.         var treeList = BRO_model.getTreeList();
  275.         if (!treeList) {
  276.             return;
  277.         }
  278.  
  279.         var newSelectedTree = null;
  280.         for (var i = 0; i < treeList.length; i++) {
  281.             if (treeList[i].treeID == treeID) {                
  282.                 newSelectedTree = treeList[i];
  283.                 break;
  284.             }
  285.         }
  286.         
  287.         var selectedTreeChanged = (!this.getSelectedTree() || !newSelectedTree 
  288.                                  || this.getSelectedTree().treeID != newSelectedTree.treeID 
  289.                                  || this.getSelectedTree().title != newSelectedTree.title
  290.                                  || this.getSelectedTree().lastUpdate != newSelectedTree.lastUpdate);
  291.         if(selectedTreeChanged) {            
  292.             this._selectedTree = newSelectedTree;
  293.  
  294.             // If we don't find the tree in the list we create a temporary item
  295.             if (!this._selectedTree) {
  296.                 var treeObject = {};
  297.                 treeObject.treeID = treeID;
  298.                 var currentUser = BRO_model.getCurrentUser();
  299.                 if (currentUser) {
  300.                     treeObject.title = currentUser.username.toLowerCase();
  301.                 } else {
  302.                     treeObject.title = BRO_locale.getString('new.button.label');
  303.                 }
  304.                 this._selectedTree = treeObject;
  305.             }
  306.  
  307.             this.closePopup();
  308.  
  309.             BRO_toolbar.treeSelectionChanged();
  310.         }
  311.         
  312.         if(!isInitializing) {
  313.             BRO_windowManager.setSelectedTree(this.getSelectedTree());
  314.         }
  315.  
  316.         this.refreshTreeListVisualComponents(startHistoryAfterSelect);
  317.  
  318.         if (startHistoryAfterSelect) {
  319.             BRO_ButtonsHandler.startOrContinueHistory();
  320.         }
  321.     },
  322.  
  323.     selectHistory : function(historyID, startHistoryAfterSelect) {
  324.         this._selectedTree = null;
  325.         BRO_windowManager.setSelectedTree(null);
  326.         this._selectedNewHistory = null;
  327.         BRO_windowManager.setSelectedNewHistory(null);
  328.         var historyList = BRO_model.getHistoryList();
  329.         if (!historyList) {
  330.             return;
  331.         }
  332.         
  333.         var newSelectedHistory = null;
  334.         for (var i = 0; i < historyList.length; i++) {
  335.             if (historyList[i].id == historyID) {
  336.                 newSelectedHistory = historyList[i];
  337.                 break;
  338.             }
  339.         }
  340.         
  341.         var selectedHistoryChanged = (!this.getSelectedHistory() || !newSelectedHistory 
  342.                                     || this.getSelectedHistory().id != newSelectedHistory.id 
  343.                                     || this.getSelectedHistory().name != newSelectedHistory.name
  344.                                     || this.getSelectedHistory().lastUpdate != newSelectedHistory.lastUpdate);        
  345.         
  346.         if (selectedHistoryChanged) {
  347.             this._selectedHistory = newSelectedHistory;
  348.  
  349.             this.closePopup();
  350.  
  351.             BRO_toolbar.treeSelectionChanged();
  352.         }
  353.  
  354.         BRO_windowManager.setSelectedHistory(this._selectedHistory);
  355.  
  356.         this.refreshTreeListVisualComponents(startHistoryAfterSelect);
  357.  
  358.         if (startHistoryAfterSelect) {
  359.             BRO_ButtonsHandler.startOrContinueHistory();
  360.         }
  361.     },
  362.  
  363.     isTreeIdInTreeList : function(treeID) {
  364.         var treeList = BRO_model.getTreeList();
  365.         if (!treeList)
  366.             return false;
  367.         for (var i = 0; i < treeList.length; i++) {
  368.             if (treeList[i].treeID == treeID) {
  369.                 return true;
  370.             }
  371.         }
  372.         return false;
  373.     },
  374.  
  375.     selectNewHistory : function(selectedNewHistory, startHistoryAfterSelect) {
  376.         this._selectedTree = null;
  377.         BRO_windowManager.setSelectedTree(null);
  378.         this._selectedHistory = null;
  379.         BRO_windowManager.setSelectedHistory(null);
  380.         // BRO_toolbar.saveSelectedTreeIntoPreferences(null);
  381.  
  382.         this._selectedNewHistory = selectedNewHistory;
  383.         BRO_windowManager.setSelectedNewHistory(selectedNewHistory);
  384.         BRO_toolbar.treeSelectionChanged();
  385.  
  386.         this.refreshTreeListVisualComponents(startHistoryAfterSelect);
  387.  
  388.         var newButtonPopup = document.getElementById('BRO_newButtonPopup');
  389.         newButtonPopup.hidePopup();
  390.         if (startHistoryAfterSelect) {
  391.             BRO_ButtonsHandler.startOrContinueHistory(forceStartNew = true);
  392.         }
  393.     },
  394.     
  395.     onClickRootTree: function () {
  396.         var currentUser = BRO_model.getCurrentUser();
  397.         var startHistoryAfterSelect = false;
  398.         var selectionChanged = (currentUser.rootTreeID != this.getSelectedTree());
  399.         if (BRO_toolbar.getRecordingMode() == RECORING_MODE_CONTINUOUS
  400.                 && BRO_toolbar.isRecording
  401.                 && selectionChanged) {
  402.             startHistoryAfterSelect = true;
  403.         } else if (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE
  404.                 && BRO_toolbar.isCurrentUrlRecorded()
  405.                 && selectionChanged) {
  406.             startHistoryAfterSelect = true;
  407.         }
  408.  
  409.         this.selectRootTree(startHistoryAfterSelect);
  410.         BRO_inButtonController._selectionChanged = selectionChanged;
  411.  
  412.         this.closePopup();        
  413.         
  414.         if (BRO_toolbar.isPearltreesPublicUrl()) {
  415.             BRO_toolbar.openSelectedTreeInCurrentTab();
  416.         }
  417.     },
  418.     
  419.     selectRootTree : function(startHistoryAfterSelect) {
  420.         var currentUser = BRO_model.getCurrentUser();
  421.         if (currentUser) {
  422.             this.selectTree(currentUser.rootTreeID, startHistoryAfterSelect);
  423.         }
  424.     },
  425.     
  426.     onClickDropZoneTree: function () {
  427.         var currentUser = BRO_model.getCurrentUser();
  428.         var startHistoryAfterSelect = false;
  429.         if (BRO_toolbar.getRecordingMode() == RECORING_MODE_CONTINUOUS
  430.                 && BRO_toolbar.isRecording
  431.                 && currentUser.rootTreeID != this.getSelectedTree()) {
  432.             startHistoryAfterSelect = true;
  433.         } else if (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE
  434.                 && BRO_toolbar.isCurrentUrlRecorded()
  435.                 && currentUser.rootTreeID != this.getSelectedTree()) {
  436.             startHistoryAfterSelect = true;
  437.         }
  438.  
  439.         this.selectDropZoneTree(startHistoryAfterSelect); 
  440.         BRO_inButtonController._selectionChanged = true;
  441.  
  442.         this.closePopup();        
  443.         
  444.         if (BRO_toolbar.isPearltreesPublicUrl()) {
  445.             BRO_toolbar.openSelectedTreeInCurrentTab();
  446.         }
  447.     },    
  448.     
  449.     selectDropZoneTree : function(startHistoryAfterSelect) {
  450.         var currentUser = BRO_model.getCurrentUser();
  451.         if(currentUser) {
  452.             this.selectTree(currentUser.dropZoneID, startHistoryAfterSelect);
  453.         }
  454.     },    
  455.  
  456.     refreshTreeListVisualComponents : function(isRecording) {
  457.         var newButton = document.getElementById('BRO_newButton');
  458.         if(!newButton) return;
  459.         var currentUser = BRO_model.getCurrentUser();
  460.         var label = "";
  461.         var tooltip = "";
  462.         if (this.getSelectedTree()) {
  463.             if (currentUser && this.getSelectedTree().treeID == currentUser.dropZoneID) {
  464.                 label = BRO_locale.getString('treeList.dropzone.selected');
  465.             } else {
  466.                 label = this.getSelectedTree().title;
  467.             }
  468.             
  469.             if(currentUser && this.getSelectedTree().treeID == currentUser.rootTreeID) {
  470.                 tooltip = BRO_locale.getString('new.button.tooltip.base.rootTreeSelected');
  471.             }
  472.             else {
  473.                 var tooltipBase = (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE)
  474.                         ? BRO_locale.getString('new.button.tooltip.base.oneByOne')
  475.                         : BRO_locale.getString('new.button.tooltip.base.continuous');
  476.                 tooltip = tooltipBase + " \"" + label + "\"";
  477.             }
  478.         } else if (this.getSelectedHistory()) {
  479.             label = this.getSelectedHistory().name;
  480.             var tooltipBase = (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE)
  481.                     ? BRO_locale.getString('new.button.tooltip.base.oneByOne')
  482.                     : BRO_locale.getString('new.button.tooltip.base.continuous');
  483.             tooltip= tooltipBase + " \""
  484.                     + this.getSelectedHistory().name + "\"";
  485.         } else if (this._selectedNewHistory) {
  486.             label = this._selectedNewHistory.name;
  487.             var tooltipBase = (BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE)
  488.                     ? BRO_locale.getString('new.button.tooltip.base.oneByOne')
  489.                     : BRO_locale.getString('new.button.tooltip.base.continuous');
  490.             tooltip = tooltipBase + " \"" + this._selectedNewHistory.name + "\"";
  491.         } else if (currentUser) {
  492.             var rootTreeName = currentUser.username.toLowerCase();
  493.             label = rootTreeName;
  494.             tooltip = BRO_locale.getString('new.button.tooltip.base.rootTreeSelected');
  495.         } else {
  496.             label = BRO_locale.getString('new.button.label');
  497.             tooltip = "";
  498.         }
  499.         if(label.length > this.MAX_CHARS_IN_BUTTON_LABEL) {
  500.             label = label.substr(0, this.MAX_CHARS_IN_BUTTON_LABEL)+"..";
  501.         }
  502.         newButton.label = label;
  503.         newButton.tooltipText = tooltip;
  504.         this.refreshTreeListTextHeader(isRecording);
  505.         this.refreshTreeListHeight();
  506.     },
  507.  
  508.     /**
  509.      * TODO setting description.value does not render well. Should fix this.
  510.      */
  511.     refreshTreeListTextHeader : function(isRecording) {
  512.         if (!isRecording) {
  513.             isRecording = (BRO_toolbar.isRecording && BRO_toolbar.getRecordingMode() == RECORING_MODE_CONTINUOUS);
  514.         }
  515.         var newButtonMenuPopupTitle = document.getElementById("BRO_newButtonMenuPopupTitle");
  516.         if(!newButtonMenuPopupTitle) return;
  517.         newButtonMenuPopupTitle.removeChild(newButtonMenuPopupTitle.firstChild);
  518.         var headerText = BRO_locale.getString('new.header');
  519.         if (isRecording) {
  520.             headerText = BRO_locale.getString('new.header.recording');
  521.         }
  522.         var textNode = document.createTextNode(headerText);
  523.         newButtonMenuPopupTitle.appendChild(textNode);
  524.     },
  525.  
  526.     onTreeListNotChanged : function() {
  527.         this.backupSelection();
  528.     },
  529.  
  530.     onTreeListLoaded : function() {
  531.         this.refreshSelectedHistory();
  532.         this.rebuildTreeListAndBackupSelection();
  533.     },
  534.  
  535.     refreshSelectedHistory : function() {
  536.         var historyList = BRO_model.getHistoryList();
  537.         if (this._selectedNewHistory && !this.getSelectedHistory() && !this.getSelectedTree() && historyList) {
  538.             // Find an history by name
  539.             var historyListLength = historyList.length;
  540.  
  541.             for (var i = historyListLength - 1; i >= 0; i--) {
  542.                 if (this._selectedNewHistory && historyList[i].name == this._selectedNewHistory.name) {
  543.                     this._selectedHistory = historyList[i];
  544.                     this._selectedNewHistory = null;
  545.                 }
  546.             }
  547.         }
  548.     },
  549.  
  550.     rebuildTreeListAndBackupSelection : function() {
  551.         this.cleanTreeListBox();
  552.         this.populateTreeListBox();
  553.         this.backupSelection();
  554.     },
  555.  
  556.     backupSelection : function() {
  557.         var treeListBox = document.getElementById('BRO_treeListBox');
  558.         if(!treeListBox) return;
  559.         var currentUser = BRO_model.getCurrentUser();
  560.         
  561.         // Handle tree case
  562.         if (this.getSelectedTree()) {            
  563.             if(currentUser && this.getSelectedTree().treeID == currentUser.rootTreeID && this.getSelectedTree().pearlCount >= MAX_PEARLS_IN_TREE) {                
  564.                 var selectedTreeID = currentUser.dropZoneID;
  565.                 this.selectDropZoneTree(false);
  566.             }
  567.             else{
  568.                 var selectedTreeID = this.getSelectedTree().treeID;            
  569.             }
  570.         }
  571.         // Handle history case
  572.         else if (this.getSelectedHistory()) {
  573.             var selectedHistoryID = this.getSelectedHistory().id;
  574.         }
  575.         // Handle new tree case
  576.         else if (this._selectedNewHistory) {
  577.             // @nothing to select
  578.         }
  579.         // If there is no tree selected we select the root tree
  580.         else if(currentUser) {
  581.             var selectedTreeID = currentUser.rootTreeID;
  582.             this.selectRootTree(false);
  583.         }
  584.         var isRootTreeSelected = selectedTreeID && currentUser && selectedTreeID == currentUser.rootTreeID;
  585.         var isDropZoneSelected = selectedTreeID && currentUser && selectedTreeID == currentUser.dropZoneID;
  586.         
  587.         // Backup selection in the treeList
  588.         treeListBox.selectItem(-1);
  589.         if(!isRootTreeSelected && !isDropZoneSelected) {
  590.             if (selectedTreeID || selectedHistoryID) {
  591.                 var itemCount = treeListBox.itemCount;
  592.                 for (var i = 0; i < itemCount; i++) {
  593.                     var item = treeListBox.getItemAtIndex(i);
  594.                     var value = this.decodeListBoxItemValue(item);
  595.     
  596.                     if ((selectedTreeID && value && value.treeID == selectedTreeID) || (selectedHistoryID && value && value.id == selectedHistoryID)) {
  597.                         
  598.                         if(treeListBox.selectedItem != item) {
  599.                             treeListBox.selectItem(item);
  600.                         }
  601.                         // Error raised by richtextbox using ensureIndexIsVisible & getNumberOfVisibleRows
  602.                         if(BRO_toolbar.isBrowserVersionGreaterOrEqual("3.0")) {
  603.                             treeListBox.ensureIndexIsVisible(i);
  604.                         
  605.                             var numVisibleRows = treeListBox.getNumberOfVisibleRows();
  606.                             if (i > numVisibleRows) {
  607.                                 treeListBox.scrollToIndex(i - Math.round(numVisibleRows / 2) + 2);
  608.                             }
  609.                         }
  610.                         break;
  611.                     }
  612.                 }
  613.             }
  614.         }        
  615.  
  616.         // Backup dropZone selection
  617.         var dropZoneButton = document.getElementById('BRO_dropZoneButton');
  618.         if (isDropZoneSelected) {
  619.             dropZoneButton.className = 'BRO_treeListBoxSpecialItemSelected';
  620.         } else {
  621.             dropZoneButton.className = 'BRO_treeListBoxSpecialItem';
  622.         }
  623.         // Backup rootTree selection
  624.         var rootTreeButton = document.getElementById('BRO_rootTreeButton');
  625.  
  626.         if (isRootTreeSelected) {
  627.             rootTreeButton.className = 'BRO_treeListBoxSpecialItemSelected';
  628.         } else {
  629.             rootTreeButton.className = 'BRO_treeListBoxSpecialItem';
  630.         }
  631.     },
  632.  
  633.     appendLoadingMessageToTreeList : function() {
  634.         this.appendItemToListBox('loading...');
  635.         this.refreshTreeListVisualComponents(false);
  636.     },
  637.  
  638.     cleanTreeListBox : function() {
  639.         var treeListBox = document.getElementById('BRO_treeListBox');
  640.         if (!treeListBox)
  641.             return;
  642.         while (treeListBox.firstChild) {
  643.             treeListBox.removeChild(treeListBox.firstChild);
  644.         }
  645.     },
  646.     
  647.     populateTreeSubList : function(event) {
  648.         var parentMenupopup = event.target;
  649.         
  650.         while(parentMenupopup.firstChild) {
  651.             parentMenupopup.removeChild(parentMenupopup.firstChild);
  652.         }        
  653.         
  654.         var treeList = BRO_model.getTreeList();
  655.         if (!treeList) return;
  656.         var listLength = treeList.length;
  657.         
  658.         for (var i = 0; i < listLength; i++) {
  659.             if(treeList[i].parentID == parentMenupopup.treeID) {
  660.                 var hasChild = false;
  661.                 for (var j = 0; j < listLength; j++) {
  662.                     if(treeList[i].treeID == treeList[j].parentID) {
  663.                         hasChild = true;
  664.                     }
  665.                 }
  666.                 if(hasChild) {
  667.                     var menu = document.createElement('menu');
  668.                     menu.setAttribute('label', treeList[i].title);
  669.                     var menupopup = document.createElement('menupopup');
  670.                     menupopup.setAttribute('onpopupshowing','BRO_inButtonController.populateTreeSubList(event)');
  671.                     menupopup.treeID = treeList[i].treeID;
  672.                     menu.appendChild(menupopup);
  673.                     parentMenupopup.appendChild(menu);
  674.                 }
  675.                 else{
  676.                     var item = document.createElement('menuitem');
  677.                     item.setAttribute('label', treeList[i].title);
  678.                     parentMenupopup.appendChild(item);                    
  679.                 }
  680.             }
  681.         }
  682.     },
  683.     
  684.     populateTreeListBox : function() {
  685.         var treeListBox = document.getElementById('BRO_treeListBox');
  686.         
  687.         // Prototype new hierarchy popups
  688.         if(!treeListBox) {            
  689.             
  690.             var popup = document.getElementById('BRO_newButtonPopup');            
  691.             var treeList = BRO_model.getTreeList();
  692.             if (!treeList) return;
  693.             var listLength = treeList.length;
  694.             
  695.             while(popup.firstChild) {
  696.                 popup.removeChild(popup.firstChild);
  697.             }
  698.             
  699.             for (var i = 0; i < listLength; i++) {
  700.                 // random parent ID
  701.                 var parentIndex = BRO_tools.getRandomNumber(listLength);
  702.                 treeList[i].parentID = treeList[parentIndex].treeID;
  703.                 
  704.                 if(treeList[i].parentID == 2) {
  705.                     var hasChild = false;
  706.                     for (var j = 0; j < listLength; j++) {
  707.                         if(treeList[i].treeID == treeList[j].parentID) {
  708.                             hasChild = true;
  709.                         }
  710.                     }
  711.                     
  712.                     if(hasChild) {
  713.                         var menu = document.createElement('menu');
  714.                         menu.setAttribute('label', treeList[i].title);
  715.                         var menupopup = document.createElement('menupopup');
  716.                         menupopup.setAttribute('onpopupshowing','BRO_inButtonController.populateTreeSubList(event)');
  717.                         menupopup.treeID = treeList[i].treeID;
  718.                         menu.appendChild(menupopup);
  719.                         popup.appendChild(menu);
  720.                     }else{
  721.                         var item = document.createElement('menuitem');
  722.                         item.setAttribute('label', treeList[i].title);
  723.                         popup.appendChild(item);
  724.                     }
  725.                 }
  726.             }
  727.  
  728.             return;
  729.         }
  730.         var currentUser = BRO_model.getCurrentUser();
  731.  
  732.         // Add default "new map" item
  733.         // var defaultItemLabel = BRO_locale.getString('treeList.default');
  734.         // var defaultItem = this.appendItemToListBox(defaultItemLabel);
  735.         // defaultItem.style.fontWeight = 'bold';
  736.         // defaultItem.addEventListener('click',
  737.         // BRO_inButtonController.onClickDefaultTreeListItem, false);
  738.  
  739.         // Add space separator
  740.         // treeListBox.appendChild(this.createTreeListLineSeparator());
  741.  
  742.         // Add a text seperator
  743.         // treeListBox.appendChild(this.createTreeListTextSeparator(BRO_locale.getString('treeList.pearltreePartTitle')));
  744.  
  745.         // Add space separator
  746.         // treeListBox.appendChild(this.createTreeListSpacerSeparator(8));
  747.  
  748.         // Prepare fetching the list
  749.         var treeList = BRO_model.getTreeList();
  750.         if (!treeList)
  751.             return;
  752.         var listLength = treeList.length;
  753.  
  754.         // Find user root tree and refresh its title
  755.         var currentUser = BRO_model.getCurrentUser();
  756.         var rootTreeTitle = document.getElementById('BRO_rootTreeTitle');
  757.         if (currentUser && currentUser.rootTreeID && rootTreeTitle) {
  758.             for (var i = 0; i < listLength; i++) {
  759.                 if (treeList[i].treeID == currentUser.rootTreeID) {
  760.                     rootTreeTitle.value = treeList[i].title;
  761.                     break;
  762.                 }
  763.             }
  764.         }
  765.  
  766.         // Add space separator
  767.         // treeListBox.appendChild(this.createTreeListSpacerSeparator(8));
  768.  
  769.         // Merge the list of current histories
  770.         var historyList = BRO_model.getHistoryList();
  771.  
  772.         if (historyList && historyList.length > 0) {
  773.             treeList = treeList.concat(historyList);
  774.         }
  775.         treeList.sort(BRO_inButtonController.sortTreeListItemByTitle);
  776.  
  777.         listLength = treeList.length;
  778.         var isSelectedTreeInList = false;
  779.  
  780.         // Populate the rest of the list
  781.         for (var i = 0; i < listLength; i++) {
  782.             var item = null;
  783.             
  784.             // If it is a tree
  785.             if (treeList[i].treeID) {
  786.                 // Add items that are not the dropZone
  787.                 if (!currentUser || (treeList[i].treeID != currentUser.rootTreeID && treeList[i].treeID != currentUser.dropZoneID)) {
  788.                     var title = treeList[i].title;
  789.                     if(treeList[i].pearlCount >= MAX_PEARLS_IN_TREE) {
  790.                         title = title + " (full)";
  791.                     }
  792.                     item = this.appendItemToListBox(title, treeList[i], true);
  793.                     item.addEventListener('click', BRO_inButtonController.onClickTreeListItem, false);
  794.                 }
  795.             }
  796.  
  797.             // If it is an history
  798.             if (treeList[i].id) {
  799.                 var title = treeList[i].name;
  800.                 if(treeList[i].pearlCount >= MAX_PEARLS_IN_TREE) {
  801.                     title = title + " (full)";
  802.                 }                
  803.                 item = this.appendItemToListBox(title, treeList[i], true);
  804.                 item.addEventListener('click', BRO_inButtonController.onClickHistoryListItem, false);
  805.             }
  806.             
  807.             // Set specific display if the item selected is full
  808.             if(item) {
  809.                 if(treeList[i].pearlCount >= MAX_PEARLS_IN_TREE) {
  810.                     item.className = 'BRO_treeFull';
  811.                 }else{
  812.                     item.className = null;
  813.                 }
  814.             }
  815.  
  816.             // We update the selected tree if needed
  817.             // @todo remove
  818.             if (this.getSelectedTree() && this.getSelectedTree().treeID == treeList[i].treeID) {
  819.                 isSelectedTreeInList = true;
  820.                 if (this.getSelectedTree().title != treeList[i].title) {                    
  821.                     this._selectedTree = treeList[i];
  822.                     this.refreshTreeListVisualComponents(BRO_toolbar.isRecording);
  823.                 }
  824.             }
  825.         }
  826.  
  827.         // Find user dropzone tree and show it at the bottom of the list
  828.         // if(BRO_toolbar.getRecordingMode() == RECORING_MODE_ONE_BY_ONE) {
  829.         //        
  830.         // // Add space separator
  831.         // treeListBox.appendChild(this.createTreeListLineSeparator());
  832.         //        
  833.         // if(currentUser && currentUser.dropZoneID) {
  834.         // for(var i=0;i<listLength;i++) {
  835.         // if(treeList[i].treeID == currentUser.dropZoneID) {
  836.         // treeList[i].title = BRO_locale.getString('treeList.dropzone');
  837.         // var item = this.appendItemToListBox(treeList[i].title, treeList[i],
  838.         // true);
  839.         // item.style.fontWeight = 'bold';
  840.         // item.addEventListener('click',
  841.         // BRO_inButtonController.onClickTreeListItem, false);
  842.         // break;
  843.         // }
  844.         // }
  845.         // }
  846.         // }
  847.  
  848.         // Add space separator
  849.         // treeListBox.appendChild(this.createTreeListSpacerSeparator(8));
  850.  
  851.         // If the selected tree is no longer in the list we select the default
  852.         // tree
  853.         // @todo remove
  854.         if (this.getSelectedTree() && !isSelectedTreeInList) {
  855.             this.selectRootTree();
  856.         }
  857.  
  858.         this.refreshTreeListHeight();
  859.     },
  860.  
  861.     sortTreeListItemByTitle : function(a, b) {
  862.         // a is a tree
  863.         if (a.treeID) {
  864.             var aTitle = a.title.toLowerCase();;
  865.         }
  866.         // a is an history
  867.         else if (a.id) {
  868.             var aTitle = a.name.toLowerCase();;
  869.         } else {
  870.             return;
  871.         }
  872.  
  873.         // b is a tree
  874.         if (b.treeID) {
  875.             var bTitle = b.title.toLowerCase();;
  876.         }
  877.         // b is an history
  878.         else if (b.id) {
  879.             var bTitle = b.name.toLowerCase();;
  880.         } else {
  881.             return;
  882.         }
  883.  
  884.         return ((aTitle < bTitle) ? -1 : ((aTitle > bTitle) ? 1 : 0));
  885.     },
  886.  
  887.     appendItemToListBox : function(title, value, encode) {
  888.         var treeListBox = document.getElementById('BRO_treeListBox');
  889.         if (!treeListBox)
  890.             return null;
  891.         if (encode) {
  892.             value = BRO_model._json.encode(value);
  893.         }
  894.         return treeListBox.appendItem(title, value);
  895.     },
  896.  
  897.     decodeListBoxItemValue : function(listItem) {
  898.         if (!listItem || !listItem.value || listItem.value == 'undefined')
  899.             return null;
  900.         return BRO_model._json.decode(listItem.value);
  901.     },
  902.  
  903.     /**
  904.      * Fix the popup height if it is bigger than the window height
  905.      * 
  906.      * We calculate the popup size because Firefox does not do it well. TODO
  907.      * find a better way to calculate the popup size.
  908.      */
  909.     refreshTreeListHeight : function() {
  910.         var treeListBox = document.getElementById('BRO_treeListBox');
  911.         if(!treeListBox) return;
  912.         var newButton = document.getElementById('BRO_newButton');
  913.         var newButtonPopup = document.getElementById('BRO_newButtonPopup');
  914.         if(!newButton || !newButtonPopup) return;
  915.         
  916.         var treeList = BRO_model.getTreeList();
  917.         var historyList = BRO_model.getHistoryList();
  918.         var treeLength = (treeList) ? treeList.length : 0;
  919.         var historyLength = (historyList) ? historyList.length : 0;
  920.         var listLength = treeLength + historyLength;
  921.         var lineHeight = 19;
  922.         var separatorHeight = 28;
  923.         var borderWidth = 2;
  924.  
  925.         var newButtonPopupHeader = document.getElementById('BRO_newButtonPopupHeader');
  926.         var headerHeight = separatorHeight;
  927.         newButtonPopupHeader.setAttribute('style', 'height:' + headerHeight+ 'px');
  928.         var listHeight = headerHeight + (lineHeight * (listLength + 2))+ separatorHeight + (borderWidth * 2);
  929.  
  930.         var windowHeight = window.outerHeight;
  931.         var listY = newButton.boxObject.height + newButton.boxObject.y;
  932.         var maxHeight = windowHeight - listY - 55;
  933.         var maxHeight = (listHeight > maxHeight) ? maxHeight : null;
  934.         newButtonPopup.setAttribute('maxheight', maxHeight);
  935.     },
  936.  
  937.     createTreeListSpacerSeparator : function(spacerHeight) {
  938.         if (!spacerHeight || spacerHeight < 1)
  939.             spacerHeight = 15; // By default 1 line height
  940.         var item = document.createElement('richlistitem');
  941.         item.className = 'BRO_treeListSeparatorItem';
  942.         item.setAttribute('selectable', 'false');
  943.         var separator = document.createElement('spacer');
  944.         separator.height = spacerHeight;
  945.         item.appendChild(separator);
  946.         return item;
  947.     },
  948.  
  949.     createTreeListTextSeparator : function(text) {
  950.         var item = document.createElement('richlistitem');
  951.         item.className = 'BRO_treeListSeparatorItem';
  952.         item.setAttribute('selectable', 'false');
  953.         item.style.fontWeight = 'bold';
  954.         // var separator = document.createTextNode(text);
  955.         var separator = document.createElement('description');
  956.         var textNode = document.createTextNode(text);
  957.         separator.appendChild(textNode);
  958.         item.appendChild(separator);
  959.         return item;
  960.     },
  961.  
  962.     createTreeListLineSeparator : function() {
  963.         var item = document.createElement('richlistitem');
  964.         item.className = 'BRO_treeListSeparatorItem';
  965.         item.setAttribute('selectable', 'false');
  966.         var separator = document.createElement('image');
  967.         separator.flex = 0;
  968.         separator.className = 'BRO_treeListSeparator';
  969.         item.appendChild(separator);
  970.         return item;
  971.     },
  972.  
  973.     onShowTreeList : function(event) {
  974.         BRO_toolbar.onUseToolbar();
  975.         // Try to back up selection
  976.         this.backupSelection();
  977.         // Refresh le list
  978.         BRO_model.getTreesAndCurrentUser();
  979.         // Refresh list size when initialized (few ms after popup shown)
  980.         BRO_tools.callWithDelay('BRO_inButtonController.refreshTreeListHeight()', 10);
  981.     },
  982.  
  983.     onKeypress : function(event) {
  984.         var newButtonPopup = document.getElementById('BRO_newButtonPopup');
  985.         if (newButtonPopup && (event.keyCode == event.DOM_VK_ESCAPE || event.keyCode == event.DOM_VK_CANCEL)) {
  986.             newButtonPopup.hidePopup();
  987.         }
  988.     }
  989. }
  990. window.addEventListener("keypress", BRO_inButtonController.onKeypress, true);
  991.